﻿using System.Collections.Generic;
using Dsl.Ped.Desktop.ModuleControllers;
using Dsl.Ped.Desktop.Modules.ErrorViewer;
using Dsl.Ped.Editor.Interfaces;
using Dsl.Ped.Framework.Messages;
using GalaSoft.MvvmLight.Messaging;

namespace Dsl.Ped.Desktop.Modules.Editor
{
    /// <summary>
    /// Controller used for the notifications of the errors occured in editor.
    /// Purpose: When the <see cref="NotifyMessage"/> is sent from some <see cref="IDslPedEditor"/>
    /// component, it can happen that it is sent twice, because it is sent from the validation method and a 
    /// validation method is executed any time the binding is updated.
    /// 
    /// To prevent multiple display of messages in the error list, we have to filter out the multiple sent messages.
    /// This filtering is happening in this controller.
    /// </summary>
    public class ErrorsNotificationController : IModuleController
    {
        /// <summary>
        /// Dictionary of the messages
        /// </summary>
        private Dictionary<object, Dictionary<string, NotifyMessage>> messageDictionary;

        /// <summary>
        /// <see cref="Messenger"/> used for the communication with the editor
        /// </summary>
        private Messenger messenger;

        /// <summary>
        /// Start listening to the <see cref="NotifyMessage"/> messages
        /// </summary>
        /// <param name="messenger"></param>
        public void Start(Messenger messenger)
        {
            this.messenger = messenger;

            this.messageDictionary = new Dictionary<object, Dictionary<string, NotifyMessage>>();

            this.messenger.Register<NotifyMessage>(this, this.OnNotifyMessage);
        }

        /// <summary>
        /// Stop listening to the <see cref="NotifyMessage"/> messages
        /// </summary>
        public void Stop()
        {
            this.messageDictionary.Clear();

            this.messenger.Unregister<NotifyMessage>(this);
        }

        /// <summary>
        /// Handler method executed when the <see cref="NotifyMessage"/> is received.
        /// </summary>
        /// <param name="notifyMessage"><see cref="NotifyMessage"/> instance</param>
        private void OnNotifyMessage(NotifyMessage notifyMessage)
        {
            this.handleDictionary(notifyMessage);

            var messages = this.TransformDictionary();
            Messenger.Default.Send<NotifyListMessage>(new NotifyListMessage(messages));
        }

        /// <summary>
        /// Handle the dictionary of <see cref="NotifyMessage"/>. In general
        /// add required <see cref="NotifyMessage"/> and remove ones. This handling
        /// prevents the insert of more instance of the same <see cref="NotifyMessage"/> in the structure. 
        /// </summary>
        /// <param name="notifyMessage"><see cref="NotifyMessage"/> to be handled</param>
        private void handleDictionary(NotifyMessage notifyMessage)
        {
            if (this.messageDictionary.ContainsKey(notifyMessage.Sender))
            {
                var propertyDictionary = this.messageDictionary[notifyMessage.Sender];
                if (propertyDictionary.ContainsKey(notifyMessage.PropertyName))
                {
                    if (string.IsNullOrEmpty(notifyMessage.Description))
                    {
                        propertyDictionary.Remove(notifyMessage.PropertyName);
                    }
                    else
                    {
                        propertyDictionary[notifyMessage.PropertyName] = notifyMessage;
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(notifyMessage.Description))
                    {
                        propertyDictionary.Add(notifyMessage.PropertyName, notifyMessage);
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(notifyMessage.Description))
                {
                    var propertyDictionary = new Dictionary<string, NotifyMessage>();
                    propertyDictionary.Add(notifyMessage.PropertyName, notifyMessage);
                    this.messageDictionary.Add(notifyMessage.Sender, propertyDictionary);
                }
            }
        }

        /// <summary>
        /// Transform the current dictionary structure containing various <see cref="NotifyMessage"/>
        /// instances into a list of <see cref="NotifyMessage"/> instances
        /// </summary>
        /// <returns></returns>
        private List<NotifyMessage> TransformDictionary()
        {
            var collection = new List<NotifyMessage>();

            foreach (var sender in this.messageDictionary)
            {
                foreach (var property in sender.Value)
                {
                    collection.Add(property.Value);
                }
            }

            return collection;
        }
    }
}
